/**
 * 
 */
package mycsveditor.editors;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.StringLiteral;

/**
 * @author dongxu
 * 
 */
public class FullnameMatcher implements IInvocationMatcher {

	// TODO change me according to real application ComponentHelper
	private static final ParameterResolver[] RESOLVERS = {
			new ParameterResolver("Map.get", 0),
			new ParameterResolver("Logger.getStringValue", 1),
			new ParameterResolver("Logger.getDoubleValue", 1),
			new ParameterResolver("Logger.getIntValue", 1),
			new ParameterResolver("Logger.getBooleanValue", 1),
			new ParameterResolver("Logger.getValue", 1),
			new ParameterResolver("Logger.checkKey", 1),
			new ParameterResolver("Logger.valueEquals", 1),
			new ParameterResolver("Logger.valueEqualsIgnoreCase", 1) };

	/**
	 * @see mycsveditor.editors.IInvocationMatcher#matches(org.eclipse.jdt.core.dom.MethodInvocation)
	 */
	@Override
	public boolean matches(MethodInvocation invoke) {
		for (ParameterResolver resolver : RESOLVERS) {
			if (resolver.match(invoke)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * @see mycsveditor.editors.IInvocationMatcher#resolveParameters(java.util.List)
	 */
	@Override
	public Set<ParameterDescriptor> resolveParameters(
			List<MethodInvocation> invokes) {
		Set<ParameterDescriptor> result = new LinkedHashSet<ParameterDescriptor>();
		for (MethodInvocation invoke : invokes) {
			for (ParameterResolver resolver : RESOLVERS) {
				ParameterDescriptor pd = resolver.resolve(invoke);
				if (pd != null) {
					result.add(pd);
					continue;
				}
			}
		}
		return result;
	}

	private static final class ParameterResolver {

		private static final Pattern TYPED_CALL_PATTERN = Pattern
				.compile("^get(.*)Value");

		private String code;

		private int position;

		public ParameterResolver(String code, int position) {
			super();
			this.code = code;
			this.position = position;
		}

		public ParameterDescriptor resolve(MethodInvocation invoke) {
			if (!match(invoke)) {
				return null;
			}
			
			Object o = invoke.arguments().get(position);
			if (!(o instanceof StringLiteral)) {
				return null;
			}
			
			StringLiteral argument = (StringLiteral) o;
			String name = "", type = "";
			name = argument.getLiteralValue();
			if (name.equals("")) {
				return null;
			}
			Matcher regexMatcher = TYPED_CALL_PATTERN
					.matcher(invoke.toString());
			if (regexMatcher.find()) {
				type = regexMatcher.group(1);
			}
			return new ParameterDescriptor(name, type);
		}

		public boolean match(MethodInvocation invoke) {
			IMethod method = (IMethod) invoke.resolveMethodBinding()
					.getJavaElement();
			String invokeFullname = method.getParent().getElementName() + "."
					+ method.getElementName();
			return invokeFullname.endsWith(code);
		}
	}

}
